#ifndef __M_ROOM_H
#define __M_ROOM_H
#include "online.hpp"
#include "db.hpp"
#include <vector>
#include <string>

#define BOARD_ROW 15   // 棋盘行数
#define BOARD_COL 15   // 棋盘列数
#define WHITE_CHESS 1  // 白子占位
#define BLACK_CHESS -1 // 黑子占位
typedef enum
{
    GAME_START,
    GAME_PLAYING,
    GAME_OVER
} room_status;

class room
{
private:
    uint64_t _room_id;                    // 房间id
    room_status _room_status;             // 房间状态
    int _player_count;                    // 房间内玩家数
    uint64_t _white_id;                   // 白棋玩家id
    uint64_t _black_id;                   // 黑棋玩家id
    user_table *_tb_user;                 // 用户信息管理句柄
    online_manager *_online_uer;          // 在线用户管理句柄
    std::vector<std::vector<int>> _board; // 棋盘

public: // 默认函数
    room(uint64_t room_id, user_table *tb_user, online_manager *online_uer) : _room_status(GAME_START), _player_count(0), _white_id(0), _black_id(0),
                                                                              _tb_user(tb_user), _online_uer(online_uer), _board(BOARD_ROW, std::vector<int>(BOARD_COL, 0))
    {
        DLOG("%lu create room success", _room_id);
    }
    ~room()
    {
        DLOG("%lu destory room success", _room_id);
    }

public: // 获取/修改房间内信息
    uint64_t getRoomID() { return _room_id; }
    room_status getRoomStatus() { return _room_status; }
    int getPlayer_count() { return _player_count; }
    uint64_t get_white_player_id() { return _white_id; }
    uint64_t get_black_player_id() { return _black_id; }

    void add_white_player(uint64_t uid)
    {
        _white_id = uid;
        _player_count++;
    }
    void add_black_player(uint64_t uid)
    {
        _black_id = uid;
        _player_count++;
    }

public: // 工具类（判断等）
    // 用于统计某棋子的串联个数(用偏移量来实现不同方向的统计)
    int chess_count(int chess_row, int chess_col, int row_offset, int col_offset)
    {
        int cur_color = _board[chess_row][chess_col];
        int count = 0; // 包含自己
        // 正方向
        while (chess_row >= 0 && chess_row < BOARD_ROW &&
               chess_col >= 0 && chess_col < BOARD_COL &&
               _board[chess_row][chess_col] == cur_color)
        {
            chess_row += row_offset;
            chess_col += col_offset;
            ++count;
        }
        // 反方向
        while (chess_row >= 0 && chess_row < BOARD_ROW &&
               chess_col >= 0 && chess_col < BOARD_COL &&
               _board[chess_row][chess_col] == cur_color)
        {
            chess_row -= row_offset;
            chess_col -= col_offset;
            ++count;
        }

        return count >= 5;
    }

    // 判断是否胜利
    uint64_t check_win(int chess_row, int chess_col, int chess_color)
    {
        uint64_t winer_id = 0;
        // 检测棋子的 “米” 的四个方向
        if (chess_count(chess_row, chess_col, 0, 1) ||
            chess_count(chess_row, chess_col, 1, 0) ||
            chess_count(chess_row, chess_col, 1, 1) ||
            chess_count(chess_row, chess_col, -1, 1))
        {
            winer_id = chess_color == WHITE_CHESS ? _white_id : _black_id;
        }

        return winer_id;
    }

public: // 请求与处理
        //
    // 将rsp的信息广播给房间内的玩家
    void broadcast(Json::Value &rsp)
    {
        // 序列化
        std::string body;
        json_util::serialize(rsp, body);
        // 获取发送链接 发送
        websocket_server::connection_ptr wconn = _online_uer->get_conn_from_room(_white_id);
        websocket_server::connection_ptr bconn = _online_uer->get_conn_from_room(_black_id);
        if (wconn.get() != nullptr)
        {
            wconn->send(body);
        }
        if (bconn.get() != nullptr)
        {
            bconn->send(body);
        }
    } // 注：若后续若要添加观众等功能时，广播方式需改变，且广播内容需筛选

    // 下棋:winner reason result(错误无winner)
    Json::Value handle_chess(Json::Value &req)
    {
        // 组织响应
        Json::Value josn_resp = req;
        josn_resp["result"] = true; // 默认正确
        josn_resp["winner"] = "0";

        int chess_row = req["row"].asInt();
        int chess_col = req["col"].asInt();
        int chess_color = req["uid"].asUInt64() == _white_id ? WHITE_CHESS : BLACK_CHESS;

        // 玩家是否在线
        if (!_online_uer->is_in_game_room(_white_id) || !_online_uer->is_in_game_room(_black_id))
        {
            uint64_t winner, loser;
            if (_online_uer->is_in_game_room(_white_id))
            {
                winner = _white_id;
                loser = _black_id;
            }
            else
            {
                winner = _black_id;
                loser = _white_id;
            }
            josn_resp["reason"] = "你的对手跑了，胜利该属于你";
            josn_resp["winner"] = std::to_string(winner);

            // 更新胜利后双方的信息
            _tb_user->win(winner);
            _tb_user->lose(loser);
            return josn_resp;
        }

        // 下棋位置是否合理(“0”未被占用)
        if (_board[chess_row][chess_col] != 0)
        {
            josn_resp["result"] = false;
            josn_resp["reason"] = "该位置已被占用";
            return josn_resp;
        }

        // 下棋
        _board[chess_row][chess_col] = chess_color;
        uint64_t winner = check_win(chess_row, chess_col, chess_color);

        // 检测是否胜利
        if (winner != 0)
        {
            josn_resp["winner"] = std::to_string(winner);
            josn_resp["reason"] = "胜利者诞生";
            return josn_resp;
        }

        // 继续游戏
        josn_resp["reason"] = "游戏继续";
        return josn_resp;
    }

    // 聊天
    Json::Value handle_chat(Json::Value &req)
    {
        // 组织响应
        Json::Value josn_resp = req;

        std::string message = req["message"].asString();
        if (message.find("妈") != std::string::npos)
        {
            josn_resp["result"] = false;
            josn_resp["reason"] = "消息中含有敏感词，发送失败";
            return josn_resp;
        }
        return josn_resp;
    }

    // 将不同的请求，调用不同的处理函数
    void handle_request(Json::Value &req)
    {
        Json::Value josn_resp;
        // 1、总错误（所有请求都可能出的错误）
        //  房间号不匹配
        if (req["room_id"].asUInt64() != _room_id)
        {
            josn_resp["result"] = false;
            josn_resp["reason"] = "房间号不匹配";

            // 广播请求
            return broadcast(josn_resp);
        }

        // 2、分发请求
        // 下棋
        if (req["optype"] == "put_chess")
        {
            josn_resp = handle_chess(req);
            // 有胜利
            uint64_t winner = josn_resp["winner"].asUInt64();
            if (winner != 0)
            {
                // 更新胜利后双方的信息
                uint64_t loser = _white_id == winner ? _white_id : _black_id;
                _tb_user->win(winner);
                _tb_user->lose(loser);
                _room_status = GAME_OVER;
            }
        }
        else if (req["optype"] == "chat") // 聊天
        {
            josn_resp = handle_chat(req);
        } // 请求未知
        else
        {
            josn_resp["optype"] = req["optype"];
            josn_resp["result"] = false;
            josn_resp["reason"] = "未知请求";
        }

        // 广播请求
        return broadcast(josn_resp);
    }

    // 退出房间（不是请求）退出时，调用即可
    void handle_exit(uint64_t uid)
    {
        // 组织响应
        if (_room_status == GAME_START)
        {
            Json::Value json_resp;
            uint64_t winner_id = (Json::UInt64)(uid == _white_id ? _black_id : _white_id);
            json_resp["optype"] = "put_chess";
            json_resp["result"] = true;
            json_resp["reason"] = "对⽅掉线，不战⽽胜！";
            json_resp["room_id"] = (Json::UInt64)_room_id;
            json_resp["uid"] = (Json::UInt64)uid;
            json_resp["row"] = -1;
            json_resp["col"] = -1;
            json_resp["winner"] = (Json::UInt64)winner_id;
            uint64_t loser_id = winner_id == _white_id ? _black_id : _white_id;
            _tb_user->win(winner_id);
            _tb_user->lose(loser_id);
            _room_status = GAME_OVER;
            broadcast(json_resp);
        }
    }
};

using room_ptr = std::shared_ptr<room>; // 房间类指针
class room_manager
{
private:
    uint64_t _next_rid; // 房间id
    std::mutex _mutex;
    user_table *_user_table;                       // 用户信息管理句柄
    online_manager *_online_user;                  // 线上用户管理权限
    std::unordered_map<uint64_t, room_ptr> _rooms; // hash<roomId, roomPtr>
    std::unordered_map<uint64_t, uint64_t> _users; // hash<userId, roomId>

public: // 默认函数
    room_manager(user_table *utab, online_manager *online_user) : _next_rid(0), _user_table(utab), _online_user(online_user)
    {
        DLOG("房间管理模块初始化完毕！");
    }
    ~room_manager()
    {
        DLOG("房间管理模块即将销毁！");
    }

public: // 房间类的管理函数
    // 创建房间
    room_ptr create_room(uint64_t wUid, uint64_t bUid)
    {
        // 用户是否在大厅
        if (!_online_user->is_in_game_hall(wUid) || !_online_user->is_in_game_hall(bUid))
        {
            uint64_t loseId = wUid;
            if (!_online_user->is_in_game_hall(bUid))
                loseId = bUid;
            Json::Value user;
            _user_table->select_by_id(loseId, user);
            DLOG("用户id:%lu,用户名：%s没有在大厅", user["id"].asUInt64(), user["username"].asCString());
            return room_ptr();
        }
        // 创建房间（初始化房间信息:玩家等）

        std::unique_lock<std::mutex> lock(_mutex);
        room_ptr newRoomPtr(new room(_next_rid, _user_table, _online_user));
        newRoomPtr->add_black_player(bUid);
        newRoomPtr->add_white_player(wUid);

        _rooms.insert(std::make_pair(_next_rid, newRoomPtr));
        _users.insert(std::make_pair(bUid, _next_rid));
        _users.insert(std::make_pair(wUid, _next_rid));
        _next_rid++;
        return newRoomPtr;
    }

    // 根据房间号查找房间
    room_ptr get_roomid_by_rid(uint64_t rid)
    {
        auto it = _rooms.find(rid);
        if (it == _rooms.end())
        {
            return room_ptr();
        }
        return it->second;
    }

    // 根据用户id查找房间
    room_ptr get_roomid_by_uid(uint64_t uid)
    {
        auto it = _users.find(uid);
        if (it == _users.end())
        {
            return room_ptr();
        }
        return get_roomid_by_rid(it->second);
    }

    // 销毁房间
    void destory_room(uint64_t rid)
    {

        room_ptr roomPtr = get_roomid_by_rid(rid);
        if (roomPtr == room_ptr())
        {
            DLOG("该房间不存在，无法销毁");
            return;
        }
        uint64_t uid1 = roomPtr->get_white_player_id();
        uint64_t uid2 = roomPtr->get_black_player_id();

        {
            std::unique_lock<std::mutex> lock(_mutex);
            _rooms.erase(rid);
            _users.erase(uid1);
            _users.erase(uid2);
        }
    }

    // 移除房间中玩家（该玩家异常，如链接断开）
    void rmove_room_user(uint64_t uid)
    {

        room_ptr roomPtr = get_roomid_by_uid(uid);
        if (roomPtr == room_ptr())
        {
            DLOG("该房间不存在,用户无法退出不存在的房间");
            return;
        }
        roomPtr->handle_exit(uid);

        // 房间要没人，才销毁
        if (roomPtr->getPlayer_count() == 0)
        {
            destory_room(roomPtr->getRoomID());
        }
        else
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _users.erase(uid);
        }
    }
};
#endif